package cn.xutongxue.interview.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import cn.xutongxue.interview.common.ResponseResult;
import cn.xutongxue.interview.constants.CommonConstant;
import cn.xutongxue.interview.constants.RedisConstant;
import cn.xutongxue.interview.constants.UserConstant;
import cn.xutongxue.interview.entity.dto.user.LoginDto;
import cn.xutongxue.interview.entity.dto.user.RegisterDto;
import cn.xutongxue.interview.entity.dto.user.UserQueryDto;
import cn.xutongxue.interview.enums.Errors;
import cn.xutongxue.interview.exception.BusinessException;
import cn.xutongxue.interview.utils.DeviceUtils;
import cn.xutongxue.interview.utils.SqlUtils;
import cn.xutongxue.interview.utils.ThrowUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.xutongxue.interview.entity.User;
import cn.xutongxue.interview.service.UserService;
import cn.xutongxue.interview.mapper.UserMapper;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBitSet;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.util.*;

/**
 * @author Administrator
 * @description 针对表【sys_user(用户表)】的数据库操作Service实现
 * @createDate 2024-09-11 16:43:44
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Resource
    private RedissonClient redissonClient;

    @Override
    public ResponseResult<Boolean> login(LoginDto loginDto, HttpServletRequest request) {
        String username = loginDto.getUsername();
        String password = loginDto.getPassword();
        String encryptPwd = SaSecureUtil.sha256(password);
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
                .eq(User::getUsername, username)
                .eq(User::getPassword, encryptPwd);
        User user = getOne(wrapper);
        if (ObjectUtils.allNull(user)) {
            return ResponseResult.fail("用户名或密码错误");
        }
        // 指定设备登录。同端互斥
        StpUtil.login(user.getId(), DeviceUtils.getRequestDevice(request));
        StpUtil.getSession().set(UserConstant.USER_LOGIN_SESSION_KEY, user);
        return ResponseResult.ok(true);
    }

    @Override
    public ResponseResult<User> getLoginUserInfo(HttpServletRequest request) {
        Object loginUserId = StpUtil.getLoginIdDefaultNull();
        if (loginUserId == null) {
            throw new BusinessException(Errors.NOT_LOGIN_ERROR);
        }
        User currentUser = this.getById((String) loginUserId);
        currentUser.setPassword("");
        return ResponseResult.ok(currentUser);

    }

    @Override
    public ResponseResult<Boolean> register(RegisterDto registerDto) {
        String username = registerDto.getUsername();
        String password = registerDto.getPassword();
        String encryptPwd = SaSecureUtil.sha256(password);
        // 判断用户是否存在
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
                .eq(User::getUsername, username);
        ThrowUtils.throwIf(getOne(wrapper) != null, new BusinessException(400501, "用户已存在"));
        User user = new User();
        user.setUsername(username);
        user.setPassword(encryptPwd);
        user.setUserRole("user");
        return save(user) ? ResponseResult.ok() : ResponseResult.fail(Errors.UNKNOWN_ERROR);
    }

    @Override
    public boolean addUserSignIn(Long userId) {
        LocalDate now = LocalDate.now();
        String key = RedisConstant.getUserSignInRedisKey(now.getYear(), userId);
        RBitSet signInBitSet = redissonClient.getBitSet(key);
        // 获取今天为今年的第几天 从1开始计数
        int offset = now.getDayOfYear();
        // 判断今天是否签到
        if (!signInBitSet.get(offset)) {
            // 未签到
            signInBitSet.set(offset, true);
        }
        // 已签到直接返回
        return true;
    }

    @Override
    public List<Integer> getUserSignInRecord(Long userId, Integer year) {
        if (year == null) {
            year = LocalDate.now().getYear();
        }

        String key = RedisConstant.getUserSignInRedisKey(year, userId);
        RBitSet signInBitSet = redissonClient.getBitSet(key);
        // 缓存BitSet到内存中，避免多次创建链接访问redis
        BitSet bitSet = signInBitSet.asBitSet();
        List<Integer> dayList = new ArrayList<>();
        // 从0开始获取第一个设置为1的索引下标
        int index = bitSet.nextSetBit(0);
        // 如果找到 则继续查找
        while (index >= 0) {
            dayList.add(index);
            index = bitSet.nextSetBit(index + 1);
        }
        return dayList;
    }

    @Override
    public Page<User> listUserByPage(UserQueryDto queryDto) {
        Integer current = queryDto.getCurrent();
        Integer pageSize = queryDto.getPageSize();
        QueryWrapper<User> queryWrapper = this.getQueryWrapper(queryDto);
        return this.page(new Page<>(current, pageSize), queryWrapper);
    }


    @Override
    public QueryWrapper<User> getQueryWrapper(UserQueryDto queryDto) {
        if (queryDto == null) {
            return new QueryWrapper<>();
        }
        String username = queryDto.getUsername();
        String nickname = queryDto.getNickname();
        String userProfile = queryDto.getUserProfile();
        String userRole = queryDto.getUserRole();
        String sortField = queryDto.getSortField();
        String sortOrder = queryDto.getSortOrder();

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(username), "username", username);
        queryWrapper.eq(StringUtils.isNotBlank(userRole), "user_role", userRole);
        queryWrapper.like(StringUtils.isNotBlank(userProfile), "user_profile", userProfile);
        queryWrapper.like(StringUtils.isNotBlank(nickname), "nickname", nickname);
        // SQL注入校验
        SqlInjectionUtils.check(sortField);
        queryWrapper.orderBy(true,
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                StrUtil.toUnderlineCase(sortField));
        return queryWrapper;

    }
}




